#include <unicode/uloc.h>
#include <string>
#include <cstring>

std::string NormalizeLocale(const std::string& locale)
{
    if (locale.empty()) {
        return "";
    }

    std::string tag;
    tag.reserve(ULOC_FULLNAME_CAPACITY);

    UErrorCode err = U_ZERO_ERROR;
    uloc_canonicalize(locale.c_str(), tag.data(), tag.capacity(), &err);
    if (U_FAILURE(err)) {
        // unable to build a proper language identifier
        printf("uloc_canonicalize(\"%s\") failed: %s", locale.c_str(), u_errorName(err));
        return "";
    }

    // Preserve "und" and "und-****" since uloc_addLikelySubtags changes "und" to
    // "en-Latn-US".
    if (tag == "und" || (tag.find_first_of("und_") == 0 && tag.size() == 8)) {
        tag = tag.data();
        return tag;
    }

    char likelyChars[ULOC_FULLNAME_CAPACITY];
    uloc_addLikelySubtags(tag.data(), likelyChars, ULOC_FULLNAME_CAPACITY, &err);
    if (U_FAILURE(err)) {
        // unable to build a proper language identifier
        printf("uloc_addLikelySubtags(\"%s\") failed: %s", tag.c_str(), u_errorName(err));
        return "";
    }

    uloc_toLanguageTag(likelyChars, tag.data(), tag.capacity(), 0, &err);
    if (U_FAILURE(err)) {
        // unable to build a proper language identifier
        printf("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars, u_errorName(err));
        return "";
    }

    printf("ICU normalized '%s' to '%s'\n", locale.c_str(), tag.c_str());
    tag = tag.data();
    return tag;
}

int main()
{
    NormalizeLocale("zh_CN.UTF-8"); // ICU normalized 'zh_CN.UTF-8' to 'zh-Hans-CN'
    NormalizeLocale("zh_CN.gbk"); // ICU normalized 'zh_CN.gbk' to 'zh-Hans-CN'
    NormalizeLocale("zh_TW.Big5"); // ICU normalized 'zh_TW.Big5' to 'zh-Hant-TW'
    NormalizeLocale("eng_VUT.UTF-8"); // ICU normalized 'eng_VUT.UTF-8' to 'en-Latn-VU'
    NormalizeLocale("zh_HK"); // ICU normalized 'zh_HK' to 'zh-Hant-HK'
    NormalizeLocale("zh.UTF-8"); // ICU normalized 'zh.UTF-8' to 'zh-Hans-CN'
    NormalizeLocale("zh.gbk"); // ICU normalized 'zh.gbk' to 'zh-Hans-CN'
    NormalizeLocale("zh.Big5"); // ICU normalized 'zh.Big5' to 'zh-Hans-CN'
    NormalizeLocale("zho"); // ICU normalized 'zho' to 'zh-Hans-CN'
    NormalizeLocale("yue"); // ICU normalized 'yue' to 'yue-Hant-HK'
    NormalizeLocale("zh_MO"); // ICU normalized 'zh_MO' to 'zh-Hant-MO'
    NormalizeLocale("zh_SG"); // ICU normalized 'zh_SG' to 'zh-Hans-SG'
    NormalizeLocale("zh-Hans"); // ICU normalized 'zh-Hans' to 'zh-Hans-CN'
    NormalizeLocale("und-Latn-US-NewYork"); // ICU normalized 'und-Latn-US-NewYork' to 'en-Latn-US-newyork'
    NormalizeLocale("und-Latn-NewYork"); // ICU normalized 'und-Latn-NewYork' to 'en-Latn-US-newyork'
    NormalizeLocale("und-US-NewYork"); // ICU normalized 'und-US-NewYork' to 'en-Latn-US-newyork'
    return 0;
}
